using UnityEngine;
using System;
using System.Collections.Generic;
using GameKit.Core;

namespace GameKitUnity.Core
{
    public sealed class EntityBehaviour : MonoBehaviour, IEntity
    {
        // PUBLIC
        public string Name
        {
            get => gameObject.name;
            set => gameObject.name = value;
        }

        public bool Enabled { get; set; } = true;
        public IEntity Entity => this;

        public EntityEvent Event => _event.Value;

        // PRIVATE
        private readonly List<IComponent> _componentList = new();
        private readonly Dictionary<Type, IComponent> _componentDict = new();
        private readonly Lazy<EntityEvent> _event = new();

        public T AddComponent<T>() where T : IComponent, new()
        {
            var component = new T();
            return AddComponent(component);
        }

        public T AddComponent<T>(T component) where T : IComponent
        {
            return AddComponent(typeof(T), component);
        }

        public T AddComponent<T>(Type type, T component) where T : IComponent
        {
            if (!_componentDict.ContainsKey(type))
            {
                component.Entity = this;
                _componentDict.Add(type, component);
                _componentList.Add(component);
                return component;
            }

            // ZxLog.Error("组件已存在", type.FullName);

            return default;
        }

        public void RemoveComponent<T>(T component) where T : IComponent
        {
            _componentDict.Remove(typeof(T));
            _componentList.Remove(component);
        }

        public new T GetComponent<T>() where T : class, IComponent
        {
            if (_componentDict.TryGetValue(typeof(T), out var component))
            {
                return component as T;
            }

            return null;
        }

        public new bool TryGetComponent<T>(out T component) where T : class, IComponent
        {
            component = GetComponent<T>();
            return component != null;
        }

        public T GetMonoBehaviour<T>() where T : class
        {
            return base.GetComponent<T>();
        }

        public bool TryGetMonoBehaviour<T>(out T component) where T : class
        {
            return base.TryGetComponent<T>(out component);
        }

        public void Register(string key, Action listener)
        {
            Event.Register(key, listener);
        }

        public void Broadcast<T>(string key, T message)
        {
            Event.Broadcast(key, message);
        }

        public void Register<T>(string key, Action<T> listener)
        {
            Event.Register(key, listener);
        }

        public void Unregister(string key, Action listener)
        {
            Event.Unregister(key, listener);
        }

        public void Unregister<T>(string key, Action<T> listener)
        {
            Event.Unregister(key, listener);
        }

        public void Unregister(string key)
        {
            Event.Unregister(key);
        }

        public void Broadcast(string key)
        {
            Event.Broadcast(key);
        }

        // /// <summary>
        // /// 消息传递
        // /// </summary>
        // /// <param name="key"></param>
        // /// <param name="message"></param>
        // public void SendMessage(string key, params object[] message)
        // {
        //     for (int i = 0; i < ComponentList.Count; i++)
        //     {
        //         ComponentList[i].OnMessage(key, message);
        //     }
        // }

        // public Coroutine StartCoroutine(IEnumerator routine)
        // {
        //     return BehaviourAgent.StartCoroutine(routine);
        // }
        //
        // public void StopCoroutine(IEnumerator routine)
        // {
        //     BehaviourAgent.StopCoroutine(routine);
        // }

        private void Start()
        {
            for (int index = 0; index < _componentList.Count; index++)
            {
                var component = _componentList[index];
                if (component.Enabled)
                {
                    component.Start();
                }
            }
        }

        private void Update()
        {
            for (int index = 0; index < _componentList.Count; index++)
            {
                var component = _componentList[index];
                if (component.Enabled)
                {
                    component.OnUpdate();
                }
            }
        }

        public void OnDestroy()
        {
            for (int index = 0; index < _componentList.Count; index++)
            {
                var component = _componentList[index];
                component.OnDestroy();
            }
        }
    }
}